package com.sifang.POI.dianping;

import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public abstract class MultiThreadsCommand implements LongTermCommand {
	
	public static final int DEFAULT_MAX_THREADS = 10;
	public static final int DEFAULT_RETRY_INTERVAL = 10000;
	private int maxThreads;
	private int retryInterval;
	private long startTime;
	private ExecutorService executorService;
	
	public MultiThreadsCommand() {
		this(DEFAULT_MAX_THREADS);
		this.setRetryInterval(DEFAULT_RETRY_INTERVAL);
	}
	
	public MultiThreadsCommand(int maxThreads) {
		setMaxThreads(maxThreads);
		resetExecutorService();
	}

	private void resetExecutorService() {
		this.executorService = Executors.newFixedThreadPool(getMaxThreads());
	}
	
	@Override
	public void execute() throws Exception {
		startTime = System.currentTimeMillis();
		System.out.println(String.format("\nexecute %s with %d threads", this.getCommandName(), this.getMaxThreads()));
		
		while (true) {
			List<? extends Runnable> works = getNextBatchWorks();
			if (works.size() == 0) {
				System.out.println(String.format("\n%s finished!", this.getCommandName()));
				break;
			}
			System.out.println(String.format("\nProcess %d workitems", works.size()));
			for (Runnable work : works) {
				this.executorService.execute(work);
			}
			this.executorService.shutdown();
			this.executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);
			this.resetExecutorService();
		}
	}

	protected abstract List<? extends Runnable> getNextBatchWorks();

	private String getCommandName() {
		String name = this.getClass().getName();
		int index = name.lastIndexOf('.');
		if (index != -1) {
			name = name.substring(index + 1);
		}
		index = name.lastIndexOf("Command");
		name = name.substring(0, index);
		return name;
	}

	public int getMaxThreads() {
		return maxThreads;
	}
	
	public int getDbReadBatchSize() {
		return DpCmd.getInstance().getDbReadBatchSize();
	}

	public void setMaxThreads(int maxThreads) {
		if (maxThreads < 1) {
			throw new IllegalArgumentException("invalid thread count"); 
		}
		this.maxThreads = maxThreads;
	}

	public synchronized int getRetryInterval() {
		return retryInterval;
	}

	public synchronized void setRetryInterval(int retryInterval) {
		this.retryInterval = retryInterval;
	}
	
	@Override
	public long getStartTime() {
		return this.startTime / 1000;
	}
	
	@Override
	public long getElapseTime() {
		return (System.currentTimeMillis() - this.startTime) / 1000;
	}
	
	public String getElapseTimeString() {
		long total = getElapseTime();
		long hour = total / 3600;
		total = total - hour * 3600;
		long minute = total / 60;
		total  = total - minute * 60;
		long second = total;
		return String.format("%02d:%02d:%02d", hour, minute, second);
	}

}
